package cn.joker.config;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.MDC;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * @author alalei
 * @date 2022年07月11日 9:46
 */
@Slf4j
@Aspect
@Order(0)
@Component
public class LogAspect {

    @Pointcut("execution(public * cn..joker.controller..*Controller.*(..))")
    public void webLog() {
    }

    /**
     * 方法调用之前调用
     *
     * @param joinPoint
     */
    @Before(value = "webLog()")
    public void doBefore(JoinPoint joinPoint) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        if (!Modifier.isPublic(method.getModifiers())) {
            return;
        }

        // 接收到请求，记录请求内容
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return;
        }
        HttpServletRequest request = attributes.getRequest();
        String ipAddr = getRemoteHost(request);
        String url = request.getRequestURI();
        String requestId = IdUtil.simpleUUID();
        MDC.put("X-B3-TraceId", requestId);
        MDC.put("ip", ipAddr);

        String methodName = request.getMethod();
        Object[] paramsArray = joinPoint.getArgs();
        String params = argsArrayToString(paramsArray);

        log.info("Req URI: {}, Req type: {}, Req params:{}", url, methodName, params);
    }

    @AfterReturning(pointcut = "webLog()", returning = "returnValue")
    public void doAfterReturning(JoinPoint joinPoint, Object returnValue) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String uri = "";
        if (requestAttributes != null) {
            uri = requestAttributes.getRequest().getRequestURI();
        }
        log.info("Req URI: {}, Req finish", uri);
        MDC.clear();
    }

    /**
     * 请求参数拼装
     *
     * @param paramsArray c
     * @return s
     */
    private String argsArrayToString(Object[] paramsArray) {
        if (paramsArray != null) {
            StringBuilder buffer = new StringBuilder();
            for (Object o : paramsArray) {
                if (!(o instanceof HttpServletRequest)
                        && !(o instanceof HttpServletResponse)
                        && !(o instanceof HttpSession)
                        && !(o instanceof MultipartFile)
                        && !(o instanceof MultipartFile[])
                    //&& !(o instanceof ImageUploadDTO)
                ) {
                    buffer.append(JSONUtil.toJsonStr(o)).append(" ");
                }
            }

            String trim = buffer.toString().trim();
            if (trim.length() > 200) {
                trim = trim.substring(0, 200) + "...";
            }
            return trim;
        }
        return "param is empty";
    }

    /**
     * 获取目标主机的ip
     *
     * @param request
     * @return
     */
    private String getRemoteHost(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    }


}
